<?php
/*
 * description：
 * author：wh
 * email：
 * createTime：{2024/5/16} {14:22} 
 */

namespace wanghua\general_utility_tools_php\oss\alicloud;


use AlibabaCloud\SDK\Sts\V20150401\Models\AssumeRoleRequest;
use AlibabaCloud\SDK\Sts\V20150401\Sts;
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
use Darabonba\OpenApi\Models\Config;
use OSS\Core\OssException;
use OSS\Credentials\StaticCredentialsProvider;
use OSS\OssClient;
use wanghua\general_utility_tools_php\Mmodel;
use wanghua\general_utility_tools_php\tool\Tools;

/**
 * 阿里云OSS存储服务工具库
 *
 * 封装了快捷方法，支持快速使用
 *
 * 功能：
 * 创建桶、查询桶（bucket），删除（必须先删除桶下面的所有文件）
 * sts临时凭证获取，用于前端Browser.js直接操作oss，上传、下载等操作
 * 上传文件、下载文件、查询文件列表
 *
 * 依赖：
 * composer require aliyuncs/oss-sdk-php
 *
 * 如果要使用临时凭证，您需要使用composer require alibabacloud/sts-20150401命令安装STS依赖，使用composer require alibabacloud/sdk命令安装PHP SDK依赖。
 *
 * Class AliyunOSS
 * @package wanghua\general_utility_tools_php\oss\alicloud
 */
class AliyunOSS
{
    public $bucket = '';//必须，且后续操作都存放在这个bucket中
    protected $provider = null;
    protected $aliyun_config = [];
    protected $ossClient = [];
    protected $file_save_path = '';//文件存储路径
    public function __construct($aliyun_config)
    {
        $this->aliyun_config = $aliyun_config;
        if(empty($aliyun_config['AccessKeyId'])||empty($aliyun_config['AccessKeySecret'])||empty($aliyun_config['bucket'])){
            throw new \Exception('OSS 配置错误');
        }
        if(empty($this->bucket)){
            $this->bucket = $aliyun_config['bucket'];
        }
        //默认存储路径
        $this->setSavePath();
        // 从环境变量中获取RAM用户的访问密钥（AccessKey ID和AccessKey Secret）。
        $accessKeyId = $aliyun_config['AccessKeyId'];//config('aliyun_config.AccessKeyId');
        $accessKeySecret = $aliyun_config['AccessKeySecret'];//config('aliyun_config.AccessKeySecret');
        // 使用代码嵌入的RAM用户的访问密钥配置访问凭证。
        $this->provider = new StaticCredentialsProvider($accessKeyId, $accessKeySecret);
        // 填写Bucket所在地域对应的Endpoint。以华东1（杭州）为例，Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
        $endpoint = $aliyun_config['endpoint'];
        $config = array(
            "provider" => $this->provider,
            "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
            // 填写Endpoint对应的Region信息，例如cn-hangzhou。
            "region" => $this->aliyun_config['region_id'],
            "endpoint" => $endpoint,
        );
        $this->ossClient = new OssClient($config);
    }


    /**
     * desc：生成临时访问凭证。
     *
     * doc:https://help.aliyun.com/zh/oss/developer-reference/authorize-access-2?spm=a2c4g.11186623.0.i6#section-8rj-9sk-q7r
     * author：wh
     */
    function getAccessToken(){
        return Mmodel::catch(function (){
            // 运行本代码示例之前，请确保已使用步骤1创建的RAM用户的访问密钥设置环境变量YOUR_ACCESS_KEY_ID和YOUR_ACCESS_KEY_SECRET。
            $config = new Config([
                'accessKeyId' => $this->aliyun_config['AccessKeyId'],//getenv('YOUR_ACCESS_KEY_ID'),
                'accessKeySecret' => $this->aliyun_config['AccessKeySecret'],//getenv('YOUR_ACCESS_KEY_SECRET'),
            ]);
            //
            $config->endpoint = $this->aliyun_config['sts_endpoint'];
            $client =  new Sts($config);

            $assumeRoleRequest = new AssumeRoleRequest([
                // roleArn填写步骤2获取的角色ARN，例如acs:ram::175708322470****:role/ramtest。
                "roleArn" => "acs:ram::1113242774600735:role/ramoss",
                // roleSessionName用于自定义角色会话名称，用来区分不同的令牌，例如填写为sessiontest。
                "roleSessionName" => "sessiontest",
                // durationSeconds用于设置临时访问凭证有效时间单位为秒，最小值为900，最大值以当前角色设定的最大会话时间为准。本示例指定有效时间为3000秒。
                "durationSeconds" => 3000,
                // policy填写自定义权限策略，用于进一步限制STS临时访问凭证的权限。如果不指定Policy，则返回的STS临时访问凭证默认拥有指定角色的所有权限。
                // 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集。
                //"policy" => ""
            ]);
            $runtime = new RuntimeOptions([
                //'http' => [
                //    'verify' => false, // 禁用SSL验证，仅限于调试
                //],
            ]);
            $result = $client->assumeRoleWithOptions($assumeRoleRequest, $runtime);
            //printf("AccessKeyId:" . $result->body->credentials->accessKeyId. PHP_EOL);
            //printf("AccessKeySecret:".$result->body->credentials->accessKeySecret.PHP_EOL);
            //printf("Expiration:".$result->body->credentials->expiration.PHP_EOL);
            //printf("SecurityToken:".$result->body->credentials->securityToken.PHP_EOL);
            return Tools::set_ok('ok',[
                'accessKeyId'=>$result->body->credentials->accessKeyId,
                'accessKeySecret'=>$result->body->credentials->accessKeySecret,
                'expiration'=>$result->body->credentials->expiration,
                'securityToken'=>$result->body->credentials->securityToken,
            ]);
        });
    }

    /**
     * desc：设置文件保存目录
     * author：wh
     * @param string $unique_id 唯一id，可以是用户id，可以是其它用于区分的标识
     * @return string
     */
    function setSavePath($unique_id=''){
        if($unique_id){
            $unique_id = $unique_id.'/';
        }
        //项目名称
        $project_name = Tools::get_project_name();
        //控制器方法路径
        $ctl = strtolower(request()->controller().'/'.request()->action());
        $this->file_save_path = $project_name.'/'.$ctl.'/'.$unique_id.date('Ymd').'/';//日期
        return $this->file_save_path;
    }
}